package com.huawei.it.qccdata.utils;

import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Map;

/**
 * @author: liminghui
 * @date: 2025/2/12 22:11
 * @version: 1.0
 * @description:
 */
public class HttpClientUtil {
    private static volatile CloseableHttpClient httpClient = createHttpClient();

    public static String post(String url, String json) {
        HttpPost httpPost = new HttpPost(url);
        // 构造消息头
        config(httpPost);
        // 构造消息实体
        StringEntity entityQuery = new StringEntity(json, "UTF-8");
        entityQuery.setContentEncoding("UTF-8");
        // 发送Json格式的数据请求
        entityQuery.setContentEncoding("application/json");
        httpPost.setEntity(entityQuery);
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "UTF-8");
            // 关闭流
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            System.out.println("http请求出现错误！！！:" + e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                System.out.println("http请求出现错误！！！:" + e.getMessage());
            }
        }
        return null;
    }

    /**
     * 表单类型的请求
     *
     * @param url
     * @param params
     */
    public static String setPostForm(String url, Map<String, Object> params) {
        HttpPost httpPost = new HttpPost(url);
        // 构造消息头
        config(httpPost);

        ArrayList<NameValuePair> nvps = new ArrayList<>();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
        }

        try {
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
        } catch (Exception e) {
            System.out.println("http请求出现错误！！！:" + e.getMessage());
        }

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "UTF-8");
            // 关闭流
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            System.out.println("http请求出现错误！！！:" + e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                System.out.println("http请求出现错误！！！:" + e.getMessage());
            }
        }
        return null;
    }

    public static String get(String url) {
        HttpGet httpGet = new HttpGet(url);
        // 构造消息头
        config(httpGet);
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet, HttpClientContext.create());
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity, "UTF-8");
            EntityUtils.consume(entity);
            return result;
        } catch (Exception e) {
            System.out.println("http请求出现错误！！！:" + e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                System.out.println("http请求出现错误！！！:" + e.getMessage());
            }
        }
        return null;
    }

    private static void config(HttpRequestBase httpRequestBase) {
        // 设置header
        // httpRequestBase.setHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
        // httpRequestBase.setHeader("Accept", "application/json");
        // httpRequestBase.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
        // httpRequestBase.setHeader("Content-type", "application/json; charset=UTF-8");
        // httpRequestBase.setHeader("Connection", "keep-alive");

        httpRequestBase.setHeader("Accept", "application/json, text/plain, */*");
        httpRequestBase.setHeader("Content-type", "application/json");
        httpRequestBase.setHeader("Content-Encoding", "gzip, deflate, br, zstd");
        httpRequestBase.setHeader("Accept-Language", "zh-CN,zh;q=0.9");
        httpRequestBase.setHeader("cookie", "QCCSESSID=11bda0ecf8cd9d18f4ba4e18e0; qcc_did=b6eaba03-fc9b-42a9-b6ed-e91e4c645695; UM_distinctid=194e098a07a368-08f89809495e0f-26001951-384000-194e098a07b5da; tfstk=gFpmBWTfAI5baDLLkUWjOPru_Wl-No61wFeOWOQZaa77krevbO7M7apAknB47RYGP-dxG1Qgjt9JMRQxlOxwJO0KJvHpcn65Q23dP7b049Sg3574Wa5PBGXGAlnycn6_V8m7v4xbS2XfshWw7TWPYGXagiPqqTSAjOyV_-PzzasNQO7V_3yPYMza71Sqq375bO7w7sk11S7pQBJrromkeXTtsKIciw-VunKvUA17G37uQRJkZsbUIa2aQLj22AKt7JcO8B_A9wLre-XM4GYAyekUET5HOhIMox2VHQRWhtp--PCDSZ5eE_cUqeXDS6JVZlyGeObfEgJEXW_JEZLwn_oLK1Byp6W2wbgA6tjH7KT0jR8e2HpfNd03zNOAATSpcx2lLnSN4INzTNXQCgo9U5N1ggslJUGglXOV129mq0VpfsS5Awnoq5N1ggslJ0mu9I1VVM_d.; acw_tc=0a47308617389449112214459e0049dea2a89d0ee1021ca016f3796c4bf0e9; CNZZDATA1254842228=1611796243-1738934887-https%253A%252F%252Fwww.baidu.com%252F%7C1738945237");
        httpRequestBase.setHeader("dbbf068d86adba414d72", "621ea41b74004c29e3a3eacda68bc51d4b80f4b79b42d9a0edbb5ea44fd38d0709eb37d1c06d408739669612b29c5127dd459391655dcf778771442668de9a2b");
        httpRequestBase.setHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
        httpRequestBase.setHeader("Origin", "https://www.qcc.com");
        httpRequestBase.setHeader("Referer", "https://www.qcc.com/web/search?key=%E5%8D%8E%E4%B8%BA%E6%8A%80%E6%9C%AF%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8");
        httpRequestBase.setHeader("Sec-Fetch-Mode", "cors");
        httpRequestBase.setHeader("Sec-Fetch-Site", "same-origin");

        RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(10 * 1000)
                .setConnectTimeout(10 * 1000)
                .setSocketTimeout(10 * 1000)
                .build();
        httpRequestBase.setConfig(config);
    }

    private static CloseableHttpClient createHttpClient() {
        ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
        LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", plainsf)
                .register("https", sslsf)
                .build();
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
        // 设置最大连接数
        cm.setMaxTotal(200);
        // 设置每个连接的路由数
        cm.setDefaultMaxPerRoute(200);
        // 请求重试处理
        HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                if (executionCount >= 5)// 重试5次
                {
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了链接，那么就重试
                    return true;

                }
                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                    return false;

                }
                if (exception instanceof InterruptedIOException) {// 超时
                    return false;
                }
                if (exception instanceof UnknownHostException) {// 目标服务器不可达
                    return false;

                }
                if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                    return false;

                }
                if (exception instanceof SSLException) {// SSL握手异常
                    return false;

                }
                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                if (!(request instanceof HttpEntityEnclosingRequest)) {// 如果请求是幂等，那么就重试
                    return true;
                }
                return false;
            }
        };
        return HttpClients.custom()
                .setConnectionManager(cm)
                .setRetryHandler(httpRequestRetryHandler)
                .build();
    }

    /**
     * 饿汉式获取HttpClient
     *
     * @return
     */
    private static CloseableHttpClient getHttpClient() {
        if (httpClient == null) {
            synchronized (HttpClientUtil.class) {
                if (httpClient == null) {
                    httpClient = createHttpClient();
                }
            }
        }
        return httpClient;
    }
}
